convert garmin_fs functions from char* -> QString (#1202)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Mon, 30 Oct 2023 15:46:07 +0000 (09:46 -0600)
committerGitHub <noreply@github.com>
Mon, 30 Oct 2023 15:46:07 +0000 (09:46 -0600)
* convert garmin_fs functions from char* -> QString.

* update comment

* make tag_type a class enum

* update garmin_fs includes

garmin_fs.cc
garmin_fs.h
garmin_txt.cc
gpx.cc
gpx.h

index d00f4a0c36aea6ed7ca2a02a8686905681606e43..148db91693aced43a026fa1e2c6a0580b31f3c08 100644 (file)
 
  */
 
-#include <cstdio>                      // for snprintf, sscanf
-#include <cstdlib>                     // for strtod
+#include "garmin_fs.h"
 
-#include <QString>                     // for QString, QStringLiteral
-#include <Qt>                          // for CaseInsensitive
+#include <QString>    // for QString
+#include <Qt>         // for CaseInsensitive
 
 #include "defs.h"
-#include "garmin_fs.h"
-#include "garmin_tables.h"             // for gt_switch_display_mode_value, gt_display_mode_symbol, gt_display_mode_symbol_and_comment, gt_display_mode_symbol_and_name
-#include "inifile.h"                   // for inifile_readstr
-#include "src/core/xmlstreamwriter.h"  // for XmlStreamWriter
+#include "inifile.h"  // for inifile_readstr
 
 
 #define MYNAME "garmin_fs"
@@ -76,130 +72,40 @@ garmin_fs_t::~garmin_fs_t()
   }
 }
 
-/* GPX - out */
-
-void
-garmin_fs_xml_convert(const int base_tag, int tag, const QString& qstr, Waypoint* waypt)
+bool
+garmin_fs_convert_category(const QString& category_name, uint16_t* category)
 {
-  // FIXME: eliminate C string copy/use here:
-  const char* cdatastr = xstrdup(qstr);
-  garmin_fs_t* gmsd = garmin_fs_t::find(waypt);
-  if (gmsd == nullptr) {
-    gmsd = garmin_fs_alloc(-1);
-    waypt->fs.FsChainAdd(gmsd);
-  }
-
-  tag -= base_tag;
-  /*
-       tt_garmin_waypt_extension, -> 0
-       tt_garmin_proximity, -> 1
-       tt_garmin_temperature,-> 2
-       tt_garmin_depth, -> 3
-       tt_garmin_display_mode, -> 4
-       tt_garmin_categories, -> 5
-       tt_garmin_category, -> 6
-       tt_garmin_addr, -> 7
-       tt_garmin_city, -> 8
-       tt_garmin_state, -> 9
-       tt_garmin_country, -> 10
-       tt_garmin_postal_code, -> 11
-       tt_garmin_phone_nr, -> 12
-  */
-  switch (tag) {
-  case 1:
-    if (*cdatastr) {
-      waypt->set_proximity(strtod(cdatastr, nullptr));
-    }
-    break;
-  case 2:
-    if (*cdatastr) {
-      waypt->set_temperature(strtod(cdatastr, nullptr));
-    }
-    break;
-  case 3:
-    if (*cdatastr) {
-      waypt->set_depth(strtod(cdatastr, nullptr));
-    }
-    break;
-  case 4:
-    if (case_ignore_strcmp(cdatastr, "SymbolOnly") == 0) {
-      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol);
-    } else if (case_ignore_strcmp(cdatastr, "SymbolAndDescription") == 0) {
-      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol_and_comment);
-    } else {
-      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol_and_name);
-    }
-    break;
-  case 6:
-    if (! garmin_fs_merge_category(cdatastr, waypt)) {
-      // There's nothing a user can really do about this (well, they could
-      // create a gpsbabel.ini that mapped them to garmin category numbers
-      // but that feature is so obscure and used in so few outputs that
-      // there's no reason to alarm the user.  Just silently disregard
-      // category names that don't map cleanly.
-      // warning(MYNAME ": Unable to convert category \"%s\"!\n", cdatastr);
+  // Is the name  "Category" followed by a number? Use that number.
+  if (category_name.startsWith(u"Category ", Qt::CaseInsensitive)) {
+    bool ok;
+    int i = category_name.mid(9).toInt(&ok);
+    if (ok && (i >= 1) && (i <= 16)) {
+      *category = (1 << --i);
+      return true;
     }
-    break;
-  case 7:
-    garmin_fs_t::set_addr(gmsd, cdatastr);
-    break;
-  case 8:
-    garmin_fs_t::set_city(gmsd, cdatastr);
-    break;
-  case 9:
-    garmin_fs_t::set_state(gmsd, cdatastr);
-    break;
-  case 10:
-    garmin_fs_t::set_country(gmsd, cdatastr);
-    break;
-  case 11:
-    garmin_fs_t::set_postal_code(gmsd, cdatastr);
-    break;
-  case 12:
-    garmin_fs_t::set_phone_nr(gmsd, cdatastr);
-    break;
   }
-  xfree(cdatastr);
-}
-
-unsigned char
-garmin_fs_convert_category(const char* category_name, uint16_t* category)
-{
-  int i;
-  int cat = 0;
-
-  // Is the name  "Category" followed by a number? Use that number.
-  if ((case_ignore_strncmp(category_name, "Category ", 9) == 0) &&
-      (1 == sscanf(category_name + 9, "%d", &i)) &&
-      (i >= 1) && (i <= 16)) {
-    cat = (1 << --i);
-  } else if (global_opts.inifile != nullptr) {
+  if (global_opts.inifile != nullptr) {
     // Do we have a gpsbabel.ini that maps category names to category #'s?
-    for (i = 0; i < 16; i++) {
+    for (int i = 0; i < 16; i++) {
       QString key = QString::number(i + 1);
       QString c = inifile_readstr(global_opts.inifile, GMSD_SECTION_CATEGORIES, key);
       if (c.compare(category_name, Qt::CaseInsensitive) == 0) {
-        cat = (1 << i);
-        break;
+        *category = (1 << i);
+        return true;
       }
     }
   }
-  if (cat == 0) {
-    return 0;
-  } else {
-    *category = cat;
-    return 1;
-  }
+  return false;
 }
 
-unsigned char
-garmin_fs_merge_category(const char* category_name, Waypoint* waypt)
+bool
+garmin_fs_merge_category(const QString& category_name, Waypoint* waypt)
 {
   uint16_t cat;
 
   // Attempt to get a textual category name to a category number.
   if (!garmin_fs_convert_category(category_name, &cat)) {
-    return 0;
+    return false;
   }
 
   garmin_fs_t* gmsd = garmin_fs_t::find(waypt);
@@ -210,5 +116,5 @@ garmin_fs_merge_category(const char* category_name, Waypoint* waypt)
     waypt->fs.FsChainAdd(gmsd);
   }
   garmin_fs_t::set_category(gmsd, cat);
-  return 1;
+  return true;
 }
index fb39b5b90ce2b20a860545f2a6cef630a48d4869..0535d85aca63d82eae044ae68cdc9adba03c4e9f 100644 (file)
 #ifndef GARMIN_FS_H
 #define GARMIN_FS_H
 
-#include <cstdint>                     // for int32_t, int16_t, uint16_t
+#include <cstdint>     // for int32_t, int16_t, uint16_t
 
-#include <QString>                     // for QString
+#include <QString>     // for QString
 
 #include "defs.h"
-#include "formspec.h"                  // for FsChainFind, kFsGmsd, FormatSpecificData
-#include "src/core/xmlstreamwriter.h"  // for XmlStreamWriter
+#include "formspec.h"  // for FormatSpecificData, kFsGmsd, FormatSpecificDataList
 
 
 /* this order is used by most devices */
@@ -219,16 +218,11 @@ garmin_fs_t* garmin_fs_alloc(int protocol);
 void garmin_fs_destroy(void* fs);
 void garmin_fs_copy(void** dest, const void* src);
 
-/* for GPX */
-void garmin_fs_xml_convert(int base_tag, int tag, const QString& qstr, Waypoint* waypt);
+/* ..convert_category: returns true=OK; false=Unable to convert category */
+bool garmin_fs_convert_category(const QString& category_name, uint16_t* category);
 
-/* common garmin_fs utilities */
-
-/* ..convert_category: returns 1=OK; 0=Unable to convert category */
-unsigned char garmin_fs_convert_category(const char* category_name, uint16_t* category);
-
-/* ..merge_category: returns 1=OK; 0=Unable to convert category */
-unsigned char garmin_fs_merge_category(const char* category_name, Waypoint* waypt);
+/* ..merge_category: returns true=OK; false=Unable to convert category */
+bool garmin_fs_merge_category(const QString& category_name, Waypoint* waypt);
 
 #define GMSD_SECTION_CATEGORIES "Garmin Categories"
 
index 8720621a10522a71a5b19e268adbe931dc550fb8..c49569445a8aa5d433ae3470131373bbb3c352c5 100644 (file)
@@ -965,7 +965,7 @@ parse_categories(const QString& str)
     QString cin = catstring.trimmed();
     if (!cin.isEmpty()) {
       uint16_t val;
-      if (!garmin_fs_convert_category(CSTR(cin), &val)) {
+      if (!garmin_fs_convert_category(cin, &val)) {
         warning(MYNAME ": Unable to convert category \"%s\" at line %d!\n", qPrintable(cin), current_line);
       } else {
         res = res | val;
diff --git a/gpx.cc b/gpx.cc
index 45c7606e5bf49b8864247cb3d3a003c0e3dec983..de176e454d16391e2eb6cc4bcbe2e5be3ee73adf 100644 (file)
--- a/gpx.cc
+++ b/gpx.cc
@@ -47,7 +47,7 @@
 #include <QtGlobal>                         // for qAsConst, QAddConst<>::Type
 
 #include "defs.h"
-#include "garmin_fs.h"                      // for garmin_fs_t, garmin_ilink_t, garmin_fs_xml_convert
+#include "garmin_fs.h"                      // for garmin_fs_t, garmin_ilink_t, garmin_fs_alloc, garmin_fs_merge_category
 #include "garmin_tables.h"                  // for gt_color_index_by_rgb, gt_color_name, gt_color_value_by_name
 #include "geocache.h"                       // for Geocache, Geocache::UtfSt...
 #include "mkshort.h"                        // for MakeShort
@@ -213,6 +213,69 @@ GpxFormat::tag_gs_cache(const QXmlStreamAttributes& attr) const
   }
 }
 
+void
+GpxFormat::tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt)
+{
+  garmin_fs_t* gmsd = garmin_fs_t::find(waypt);
+  if (gmsd == nullptr) {
+    gmsd = garmin_fs_alloc(-1);
+    waypt->fs.FsChainAdd(gmsd);
+  }
+
+  switch (tag) {
+  case tag_type::garmin_wpt_proximity:
+    waypt->set_proximity(text.toDouble());
+    break;
+  case tag_type::garmin_wpt_temperature:
+    waypt->set_temperature(text.toFloat());
+    break;
+  case tag_type::garmin_wpt_depth:
+    waypt->set_depth(text.toDouble());
+    break;
+  case tag_type::garmin_wpt_display_mode:
+    // element DispalyMode value is case sensitive.
+    if (text == u"SymbolOnly") {
+      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol);
+    } else if (text == u"SymbolAndDescription") {
+      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol_and_comment);
+    } else {
+      garmin_fs_t::set_display(gmsd, gt_display_mode_symbol_and_name);
+    }
+    break;
+  case tag_type::garmin_wpt_category:
+    if (!garmin_fs_merge_category(text, waypt)) {
+      // There's nothing a user can really do about this (well, they could
+      // create a gpsbabel.ini that mapped them to garmin category numbers
+      // but that feature is so obscure and used in so few outputs that
+      // there's no reason to alarm the user.  Just silently disregard
+      // category names that don't map cleanly.
+      // warning(MYNAME ": Unable to convert category \"%s\"!\n", CSTR(text));
+    }
+    break;
+  case tag_type::garmin_wpt_addr:
+    garmin_fs_t::set_addr(gmsd, text);
+    break;
+  case tag_type::garmin_wpt_city:
+    garmin_fs_t::set_city(gmsd, text);
+    break;
+  case tag_type::garmin_wpt_state:
+    garmin_fs_t::set_state(gmsd, text);
+    break;
+  case tag_type::garmin_wpt_country:
+    garmin_fs_t::set_country(gmsd, text);
+    break;
+  case tag_type::garmin_wpt_postal_code:
+    garmin_fs_t::set_postal_code(gmsd, text);
+    break;
+  case tag_type::garmin_wpt_phone_nr:
+    garmin_fs_t::set_phone_nr(gmsd, text);
+    break;
+  default:
+    // do nothing
+    break;
+  }
+}
+
 void
 GpxFormat::start_something_else(QStringView el, const QXmlStreamAttributes& attr)
 {
@@ -318,69 +381,70 @@ GpxFormat::gpx_start(QStringView el, const QXmlStreamAttributes& attr)
 
   tag_mapping tag = get_tag(current_tag);
   switch (tag.type) {
-  case tt_gpx:
+  case tag_type::gpx:
     tag_gpx(attr);
     break;
-  case tt_link:
+  case tag_type::link:
     if (attr.hasAttribute(QLatin1String("href"))) {
       link_url = attr.value(QLatin1String("href")).toString();
     }
     break;
-  case tt_wpt:
+  case tag_type::wpt:
     tag_wpt(attr);
     break;
-  case tt_wpttype_link:
+  case tag_type::wpttype_link:
     if (attr.hasAttribute(QLatin1String("href"))) {
       link_url = attr.value(QLatin1String("href")).toString();
     }
     break;
-  case tt_rte:
+  case tag_type::rte:
     rte_head = new route_head;
     route_add_head(rte_head);
     rh_link_ = new UrlLink;
     fs_ptr = &rte_head->fs;
     break;
-  case tt_rte_rtept:
+  case tag_type::rte_rtept:
     tag_wpt(attr);
     break;
-  case tt_trk:
+  case tag_type::trk:
     trk_head = new route_head;
     track_add_head(trk_head);
     rh_link_ = new UrlLink;
     fs_ptr = &trk_head->fs;
     break;
-  case tt_trk_trkseg_trkpt:
+  case tag_type::trk_trkseg_trkpt:
     tag_wpt(attr);
     if (next_trkpt_is_new_seg) {
       wpt_tmp->wpt_flags.new_trkseg = 1;
       next_trkpt_is_new_seg = 0;
     }
     break;
-  case tt_rte_link:
-  case tt_trk_link:
+  case tag_type::rte_link:
+  case tag_type::trk_link:
     if (attr.hasAttribute(QLatin1String("href"))) {
       link_url = attr.value(QLatin1String("href")).toString();
     }
     break;
-  case tt_unknown:
+  case tag_type::unknown:
     start_something_else(el, attr);
     return;
-  case tt_cache:
+  case tag_type::cache:
     tag_gs_cache(attr);
     break;
-  case tt_cache_log_wpt:
+  case tag_type::cache_log_wpt:
     if (opt_logpoint) {
       tag_log_wpt(attr);
     }
     break;
-  case tt_cache_desc_long:
-  case tt_cache_desc_short:
+  case tag_type::cache_desc_long:
+  case tag_type::cache_desc_short:
     tag_cache_desc(attr);
     break;
-  case tt_cache_placer:
+  case tag_type::cache_placer:
     if (attr.hasAttribute(QLatin1String("id"))) {
       wpt_tmp->AllocGCData()->placer_id = attr.value(QLatin1String("id")).toInt();
     }
+    break;
   default:
     break;
   }
@@ -470,44 +534,44 @@ GpxFormat::gpx_end(QStringView /*unused*/)
   /*
    * First, the tags that are file-global.
    */
-  case tt_name:
+  case tag_type::name:
     gpx_add_to_global(gpx_global->name, cdatastr);
     break;
-  case tt_desc:
+  case tag_type::desc:
     gpx_add_to_global(gpx_global->desc, cdatastr);
     break;
-  case tt_author:
+  case tag_type::author:
     gpx_add_to_global(gpx_global->author, cdatastr);
     break;
-  case tt_email:
+  case tag_type::email:
     gpx_add_to_global(gpx_global->email, cdatastr);
     break;
-  case tt_url:
+  case tag_type::url:
     gpx_add_to_global(gpx_global->url, cdatastr);
     break;
-  case tt_urlname:
+  case tag_type::urlname:
     gpx_add_to_global(gpx_global->urlname, cdatastr);
     break;
-  case tt_keywords:
+  case tag_type::keywords:
     gpx_add_to_global(gpx_global->keywords, cdatastr);
     break;
-  case tt_link:
+  case tag_type::link:
     (gpx_global->link).AddUrlLink(UrlLink(link_url, link_text, link_type));
     link_type.clear();
     link_text.clear();
     link_url.clear();
     break;
-  case tt_link_text:
+  case tag_type::link_text:
     link_text = cdatastr;
     break;
-  case tt_link_type:
+  case tag_type::link_type:
     link_type = cdatastr;
     break;
 
   /*
    * Waypoint-specific tags.
    */
-  case tt_wpt:
+  case tag_type::wpt:
     if (link_) {
       if (!link_->url_.isEmpty()) {
         wpt_tmp->AddUrlLink(*link_);
@@ -525,40 +589,40 @@ GpxFormat::gpx_end(QStringView /*unused*/)
     wpt_tmp = nullptr;
     fs_ptr = nullptr;
     break;
-  case tt_cache_name:
+  case tag_type::cache_name:
     wpt_tmp->notes = cdatastr;
     break;
-  case tt_cache_container:
+  case tag_type::cache_container:
     wpt_tmp->AllocGCData()->set_container(cdatastr);
     break;
-  case tt_cache_type:
+  case tag_type::cache_type:
     wpt_tmp->AllocGCData()->set_type(cdatastr);
     break;
-  case tt_cache_difficulty:
+  case tag_type::cache_difficulty:
     wpt_tmp->AllocGCData()->diff = cdatastr.toFloat() * 10;
     break;
-  case tt_cache_hint:
+  case tag_type::cache_hint:
     wpt_tmp->AllocGCData()->hint = cdatastr;
     break;
-  case tt_cache_desc_long: {
+  case tag_type::cache_desc_long: {
     Geocache* gc_data = wpt_tmp->AllocGCData();
     gc_data->desc_long.is_html = cache_descr_is_html;
     gc_data->desc_long.utf_string = cdatastr;
   }
   break;
-  case tt_cache_desc_short: {
+  case tag_type::cache_desc_short: {
     Geocache* gc_data = wpt_tmp->AllocGCData();
     gc_data->desc_short.is_html = cache_descr_is_html;
     gc_data->desc_short.utf_string = cdatastr;
   }
   break;
-  case tt_cache_terrain:
+  case tag_type::cache_terrain:
     wpt_tmp->AllocGCData()->terr = cdatastr.toFloat() * 10;
     break;
-  case tt_cache_placer:
+  case tag_type::cache_placer:
     wpt_tmp->AllocGCData()->placer = cdatastr;
     break;
-  case tt_cache_log_date:
+  case tag_type::cache_log_date:
     gc_log_date = xml_parse_time(cdatastr);
     break;
   /*
@@ -566,51 +630,51 @@ GpxFormat::gpx_end(QStringView /*unused*/)
    * if this is the first "found it" for this waypt, just use the
    * last date we saw in this log.
    */
-  case tt_cache_log_type:
+  case tag_type::cache_log_type:
     if ((cdatastr.compare(u"Found it") == 0) &&
         (!wpt_tmp->gc_data->last_found.isValid())) {
       wpt_tmp->AllocGCData()->last_found = gc_log_date;
     }
     gc_log_date = gpsbabel::DateTime();
     break;
-  case tt_cache_favorite_points:
+  case tag_type::cache_favorite_points:
     wpt_tmp->AllocGCData()->favorite_points = cdatastr.toInt();
     break;
-  case tt_cache_personal_note:
+  case tag_type::cache_personal_note:
     wpt_tmp->AllocGCData()->personal_note = cdatastr;
     break;
 
   /*
    * Garmin-waypoint-specific tags.
    */
-  case tt_garmin_wpt_proximity:
-  case tt_garmin_wpt_temperature:
-  case tt_garmin_wpt_depth:
-  case tt_garmin_wpt_display_mode:
-  case tt_garmin_wpt_category:
-  case tt_garmin_wpt_addr:
-  case tt_garmin_wpt_city:
-  case tt_garmin_wpt_state:
-  case tt_garmin_wpt_country:
-  case tt_garmin_wpt_postal_code:
-  case tt_garmin_wpt_phone_nr:
-    garmin_fs_xml_convert(tt_garmin_wpt_extensions, tag.type, cdatastr, wpt_tmp);
+  case tag_type::garmin_wpt_proximity:
+  case tag_type::garmin_wpt_temperature:
+  case tag_type::garmin_wpt_depth:
+  case tag_type::garmin_wpt_display_mode:
+  case tag_type::garmin_wpt_category:
+  case tag_type::garmin_wpt_addr:
+  case tag_type::garmin_wpt_city:
+  case tag_type::garmin_wpt_state:
+  case tag_type::garmin_wpt_country:
+  case tag_type::garmin_wpt_postal_code:
+  case tag_type::garmin_wpt_phone_nr:
+    tag_garmin_fs(tag.type, cdatastr, wpt_tmp);
     break;
 
   /*
    * Humminbird-waypoint-specific tags.
    */
-  case tt_humminbird_wpt_depth:
-  case tt_humminbird_trk_trkseg_trkpt_depth:
+  case tag_type::humminbird_wpt_depth:
+  case tag_type::humminbird_trk_trkseg_trkpt_depth:
     wpt_tmp->set_depth(cdatastr.toDouble() / 100.0);
     break;
   /*
    * Route-specific tags.
    */
-  case tt_rte_name:
+  case tag_type::rte_name:
     rte_head->rte_name = cdatastr;
     break;
-  case tt_rte:
+  case tag_type::rte:
     if (rh_link_) {
       if (!rh_link_->url_.isEmpty()) {
         rte_head->rte_urls.AddUrlLink(*rh_link_);
@@ -620,7 +684,7 @@ GpxFormat::gpx_end(QStringView /*unused*/)
     }
     fs_ptr = nullptr;
     break;
-  case tt_rte_rtept:
+  case tag_type::rte_rtept:
     if (link_) {
       if (!link_->url_.isEmpty()) {
         wpt_tmp->AddUrlLink(*link_);
@@ -636,28 +700,28 @@ GpxFormat::gpx_end(QStringView /*unused*/)
     wpt_tmp = nullptr;
     fs_ptr = nullptr;
     break;
-  case tt_rte_desc:
+  case tag_type::rte_desc:
     rte_head->rte_desc = cdatastr;
     break;
-  case tt_garmin_rte_display_color:
+  case tag_type::garmin_rte_display_color:
     rte_head->line_color.bbggrr = gt_color_value_by_name(cdatastr);
     break;
-  case tt_rte_link:
+  case tag_type::rte_link:
     rte_head->rte_urls.AddUrlLink(UrlLink(link_url, link_text, link_type));
     link_type.clear();
     link_text.clear();
     link_url.clear();
     break;
-  case tt_rte_number:
+  case tag_type::rte_number:
     rte_head->rte_num = cdatastr.toInt();
     break;
   /*
    * Track-specific tags.
    */
-  case tt_trk_name:
+  case tag_type::trk_name:
     trk_head->rte_name = cdatastr;
     break;
-  case tt_trk:
+  case tag_type::trk:
     if (rh_link_) {
       if (!rh_link_->url_.isEmpty()) {
         trk_head->rte_urls.AddUrlLink(*rh_link_);
@@ -667,11 +731,11 @@ GpxFormat::gpx_end(QStringView /*unused*/)
     }
     fs_ptr = nullptr;
     break;
-  case tt_trk_trkseg:
+  case tag_type::trk_trkseg:
     next_trkpt_is_new_seg = 1;
     fs_ptr = nullptr;
     break;
-  case tt_trk_trkseg_trkpt:
+  case tag_type::trk_trkseg_trkpt:
     if (link_) {
       if (!link_->url_.isEmpty()) {
         wpt_tmp->AddUrlLink(*link_);
@@ -687,117 +751,117 @@ GpxFormat::gpx_end(QStringView /*unused*/)
     wpt_tmp = nullptr;
     fs_ptr = nullptr;
     break;
-  case tt_trk_desc:
+  case tag_type::trk_desc:
     trk_head->rte_desc = cdatastr;
     break;
-  case tt_garmin_trk_display_color:
+  case tag_type::garmin_trk_display_color:
     trk_head->line_color.bbggrr = gt_color_value_by_name(cdatastr);
     break;
-  case tt_trk_link:
+  case tag_type::trk_link:
     trk_head->rte_urls.AddUrlLink(UrlLink(link_url, link_text, link_type));
     link_type.clear();
     link_text.clear();
     link_url.clear();
     break;
-  case tt_trk_number:
+  case tag_type::trk_number:
     trk_head->rte_num = cdatastr.toInt();
     break;
-  case tt_trk_trkseg_trkpt_course:
+  case tag_type::trk_trkseg_trkpt_course:
     wpt_tmp->set_course(cdatastr.toDouble());
     break;
-  case tt_trk_trkseg_trkpt_speed:
+  case tag_type::trk_trkseg_trkpt_speed:
     wpt_tmp->set_speed(cdatastr.toDouble());
     break;
-  case tt_trk_trkseg_trkpt_heartrate:
+  case tag_type::trk_trkseg_trkpt_heartrate:
     wpt_tmp->heartrate = cdatastr.toDouble();
     break;
-  case tt_trk_trkseg_trkpt_cadence:
+  case tag_type::trk_trkseg_trkpt_cadence:
     wpt_tmp->cadence = cdatastr.toDouble();
     break;
 
   /*
    * Items that are actually in multiple categories.
    */
-  case tt_rte_url:
-  case tt_trk_url:
+  case tag_type::rte_url:
+  case tag_type::trk_url:
     rh_link_->url_ = cdatastr;
     break;
-  case tt_rte_urlname:
-  case tt_trk_urlname:
+  case tag_type::rte_urlname:
+  case tag_type::trk_urlname:
     rh_link_->url_link_text_ = cdatastr;
     break;
-  case tt_rte_link_text:
-  case tt_trk_link_text:
+  case tag_type::rte_link_text:
+  case tag_type::trk_link_text:
     link_text = cdatastr;
     break;
-  case tt_rte_link_type:
-  case tt_trk_link_type:
+  case tag_type::rte_link_type:
+  case tag_type::trk_link_type:
     link_type = cdatastr;
     break;
-  case tt_wpttype_ele:
+  case tag_type::wpttype_ele:
     wpt_tmp->altitude = cdatastr.toDouble();
     break;
-  case tt_wpttype_name:
+  case tag_type::wpttype_name:
     wpt_tmp->shortname = cdatastr;
     break;
-  case tt_wpttype_sym:
+  case tag_type::wpttype_sym:
     wpt_tmp->icon_descr = cdatastr;
     break;
-  case tt_wpttype_time:
+  case tag_type::wpttype_time:
     wpt_tmp->SetCreationTime(xml_parse_time(cdatastr));
     break;
-  case tt_wpttype_magvar:
+  case tag_type::wpttype_magvar:
     if (wpt_fsdata == nullptr) {
       wpt_fsdata = new gpx_wpt_fsdata;
     }
     wpt_fsdata->magvar = cdatastr;
     break;
-  case tt_wpttype_geoidheight:
+  case tag_type::wpttype_geoidheight:
     wpt_tmp->set_geoidheight(cdatastr.toDouble());
     break;
-  case tt_wpttype_cmt:
+  case tag_type::wpttype_cmt:
     wpt_tmp->description = cdatastr;
     break;
-  case tt_wpttype_desc:
+  case tag_type::wpttype_desc:
     wpt_tmp->notes = cdatastr;
     break;
-  case tt_wpttype_src:
+  case tag_type::wpttype_src:
     if (wpt_fsdata == nullptr) {
       wpt_fsdata = new gpx_wpt_fsdata;
     }
     wpt_fsdata->src = cdatastr;
     break;
-  case tt_wpttype_type:
+  case tag_type::wpttype_type:
     if (wpt_fsdata == nullptr) {
       wpt_fsdata = new gpx_wpt_fsdata;
     }
     wpt_fsdata->type = cdatastr;
     break;
-  case tt_wpttype_pdop:
+  case tag_type::wpttype_pdop:
     wpt_tmp->pdop = cdatastr.toFloat();
     break;
-  case tt_wpttype_hdop:
+  case tag_type::wpttype_hdop:
     wpt_tmp->hdop = cdatastr.toFloat();
     break;
-  case tt_wpttype_vdop:
+  case tag_type::wpttype_vdop:
     wpt_tmp->vdop = cdatastr.toFloat();
     break;
-  case tt_wpttype_ageofdgpsdata:
+  case tag_type::wpttype_ageofdgpsdata:
     if (wpt_fsdata == nullptr) {
       wpt_fsdata = new gpx_wpt_fsdata;
     }
     wpt_fsdata->ageofdgpsdata = cdatastr;
     break;
-  case tt_wpttype_dgpsid:
+  case tag_type::wpttype_dgpsid:
     if (wpt_fsdata == nullptr) {
       wpt_fsdata = new gpx_wpt_fsdata;
     }
     wpt_fsdata->dgpsid = cdatastr;
     break;
-  case tt_wpttype_sat:
+  case tag_type::wpttype_sat:
     wpt_tmp->sat = cdatastr.toInt();
     break;
-  case tt_wpttype_fix:
+  case tag_type::wpttype_fix:
     if (cdatastr == QLatin1String("none")) {
       wpt_tmp->fix = fix_none;
     } else if (cdatastr == QLatin1String("2d")) {
@@ -812,25 +876,25 @@ GpxFormat::gpx_end(QStringView /*unused*/)
       wpt_tmp->fix = fix_unknown;
     }
     break;
-  case tt_wpttype_url:
+  case tag_type::wpttype_url:
     link_->url_ = cdatastr;
     break;
-  case tt_wpttype_urlname:
+  case tag_type::wpttype_urlname:
     link_->url_link_text_ = cdatastr;
     break;
-  case tt_wpttype_link:
+  case tag_type::wpttype_link:
     waypt_add_url(wpt_tmp, link_url, link_text, link_type);
     link_type.clear();
     link_text.clear();
     link_url.clear();
     break;
-  case tt_wpttype_link_text:
+  case tag_type::wpttype_link_text:
     link_text = cdatastr;
     break;
-  case tt_wpttype_link_type:
+  case tag_type::wpttype_link_type:
     link_type = cdatastr;
     break;
-  case tt_unknown:
+  case tag_type::unknown:
     end_something_else();
     return;
   default:
diff --git a/gpx.h b/gpx.h
index a658404bac46a0ed167e98c1bbdad06ae46f1000..c0d0218ac050fece9052ec4c83d2f48d715b0b2d 100644 (file)
--- a/gpx.h
+++ b/gpx.h
@@ -95,112 +95,112 @@ private:
     gpxpt_route
   };
 
-  enum tag_type {
-    tt_unknown = 0,
-    tt_gpx,
-
-    tt_name,           /* Optional file-level info */
-    tt_desc,
-    tt_author,
-    tt_email,
-    tt_url,
-    tt_urlname,
-    tt_keywords,
-    tt_link,
-    tt_link_text,
-    tt_link_type,
-
-    tt_wpt,
-    tt_wpttype_ele,
-    tt_wpttype_time,
-    tt_wpttype_magvar,
-    tt_wpttype_geoidheight,
-    tt_wpttype_name,
-    tt_wpttype_cmt,
-    tt_wpttype_desc,
-    tt_wpttype_src,
-    tt_wpttype_url,            /* Not in GPX 1.1 */
-    tt_wpttype_urlname,        /* Not in GPX 1.1 */
-    tt_wpttype_link,           /* New in GPX 1.1 */
-    tt_wpttype_link_text,      /* New in GPX 1.1 */
-    tt_wpttype_link_type,      /* New in GPX 1.1 */
-    tt_wpttype_sym,
-    tt_wpttype_type,
-    tt_wpttype_fix,
-    tt_wpttype_sat,
-    tt_wpttype_hdop,           /* HDOPS are common for all three */
-    tt_wpttype_vdop,           /* VDOPS are common for all three */
-    tt_wpttype_pdop,           /* PDOPS are common for all three */
-    tt_wpttype_ageofdgpsdata,
-    tt_wpttype_dgpsid,
-    tt_cache,
-    tt_cache_name,
-    tt_cache_container,
-    tt_cache_type,
-    tt_cache_difficulty,
-    tt_cache_terrain,
-    tt_cache_hint,
-    tt_cache_desc_short,
-    tt_cache_desc_long,
-    tt_cache_log_wpt,
-    tt_cache_log_type,
-    tt_cache_log_date,
-    tt_cache_placer,
-    tt_cache_favorite_points,
-    tt_cache_personal_note,
-
-    tt_wpt_extensions,
-
-    tt_garmin_wpt_extensions,  /* don't change this order */
-    tt_garmin_wpt_proximity,
-    tt_garmin_wpt_temperature,
-    tt_garmin_wpt_depth,
-    tt_garmin_wpt_display_mode,
-    tt_garmin_wpt_categories,
-    tt_garmin_wpt_category,
-    tt_garmin_wpt_addr,
-    tt_garmin_wpt_city,
-    tt_garmin_wpt_state,
-    tt_garmin_wpt_country,
-    tt_garmin_wpt_postal_code,
-    tt_garmin_wpt_phone_nr,            /* don't change this order */
-
-    tt_rte,
-    tt_rte_name,
-    tt_rte_desc,
-    tt_rte_cmt,
-    tt_rte_url,                /* Not in GPX 1.1 */
-    tt_rte_urlname,    /* Not in GPX 1.1 */
-    tt_rte_link,               /* New in GPX 1.1 */
-    tt_rte_link_text,  /* New in GPX 1.1 */
-    tt_rte_link_type,  /* New in GPX 1.1 */
-    tt_rte_number,
-    tt_garmin_rte_display_color,
-    tt_rte_rtept,
-    tt_trk,
-    tt_trk_desc,
-    tt_trk_name,
-    tt_trk_trkseg,
-    tt_trk_url,                /* Not in GPX 1.1 */
-    tt_trk_urlname,    /* Not in GPX 1.1 */
-    tt_trk_link,               /* New in GPX 1.1 */
-    tt_trk_link_text,  /* New in GPX 1.1 */
-    tt_trk_link_type,  /* New in GPX 1.1 */
-    tt_trk_number,
-    tt_garmin_trk_display_color,
-    tt_trk_trkseg_trkpt,
-    tt_trk_trkseg_trkpt_course,        /* Not in GPX 1.1 */
-    tt_trk_trkseg_trkpt_speed, /* Not in GPX 1.1 */
-    tt_trk_trkseg_trkpt_heartrate,
-    tt_trk_trkseg_trkpt_cadence,
-
-    tt_humminbird_wpt_depth,
-    tt_humminbird_wpt_status,
-    tt_humminbird_trk_trkseg_trkpt_depth,
+  enum class tag_type {
+    unknown = 0,
+    gpx,
+
+    name,              /* Optional file-level info */
+    desc,
+    author,
+    email,
+    url,
+    urlname,
+    keywords,
+    link,
+    link_text,
+    link_type,
+
+    wpt,
+    wpttype_ele,
+    wpttype_time,
+    wpttype_magvar,
+    wpttype_geoidheight,
+    wpttype_name,
+    wpttype_cmt,
+    wpttype_desc,
+    wpttype_src,
+    wpttype_url,               /* Not in GPX 1.1 */
+    wpttype_urlname,   /* Not in GPX 1.1 */
+    wpttype_link,              /* New in GPX 1.1 */
+    wpttype_link_text, /* New in GPX 1.1 */
+    wpttype_link_type, /* New in GPX 1.1 */
+    wpttype_sym,
+    wpttype_type,
+    wpttype_fix,
+    wpttype_sat,
+    wpttype_hdop,              /* HDOPS are common for all three */
+    wpttype_vdop,              /* VDOPS are common for all three */
+    wpttype_pdop,              /* PDOPS are common for all three */
+    wpttype_ageofdgpsdata,
+    wpttype_dgpsid,
+    cache,
+    cache_name,
+    cache_container,
+    cache_type,
+    cache_difficulty,
+    cache_terrain,
+    cache_hint,
+    cache_desc_short,
+    cache_desc_long,
+    cache_log_wpt,
+    cache_log_type,
+    cache_log_date,
+    cache_placer,
+    cache_favorite_points,
+    cache_personal_note,
+
+    wpt_extensions,
+
+    garmin_wpt_extensions,
+    garmin_wpt_proximity,
+    garmin_wpt_temperature,
+    garmin_wpt_depth,
+    garmin_wpt_display_mode,
+    garmin_wpt_categories,
+    garmin_wpt_category,
+    garmin_wpt_addr,
+    garmin_wpt_city,
+    garmin_wpt_state,
+    garmin_wpt_country,
+    garmin_wpt_postal_code,
+    garmin_wpt_phone_nr,
+
+    rte,
+    rte_name,
+    rte_desc,
+    rte_cmt,
+    rte_url,           /* Not in GPX 1.1 */
+    rte_urlname,       /* Not in GPX 1.1 */
+    rte_link,          /* New in GPX 1.1 */
+    rte_link_text,     /* New in GPX 1.1 */
+    rte_link_type,     /* New in GPX 1.1 */
+    rte_number,
+    garmin_rte_display_color,
+    rte_rtept,
+    trk,
+    trk_desc,
+    trk_name,
+    trk_trkseg,
+    trk_url,           /* Not in GPX 1.1 */
+    trk_urlname,       /* Not in GPX 1.1 */
+    trk_link,          /* New in GPX 1.1 */
+    trk_link_text,     /* New in GPX 1.1 */
+    trk_link_type,     /* New in GPX 1.1 */
+    trk_number,
+    garmin_trk_display_color,
+    trk_trkseg_trkpt,
+    trk_trkseg_trkpt_course,   /* Not in GPX 1.1 */
+    trk_trkseg_trkpt_speed,    /* Not in GPX 1.1 */
+    trk_trkseg_trkpt_heartrate,
+    trk_trkseg_trkpt_cadence,
+
+    humminbird_wpt_depth,
+    humminbird_wpt_status,
+    humminbird_trk_trkseg_trkpt_depth,
   };
 
   struct tag_mapping {
-    tag_type type{tt_unknown}; /* enum from above for this tag */
+    tag_type type{tag_type::unknown}; /* enum from above for this tag */
     /*
      * passthrough should be true for
      * 1) The gpx 1.1 extensions element and any descendents.
@@ -221,6 +221,7 @@ private:
   void tag_wpt(const QXmlStreamAttributes& attr);
   void tag_cache_desc(const QXmlStreamAttributes& attr);
   void tag_gs_cache(const QXmlStreamAttributes& attr) const;
+  void tag_garmin_fs(tag_type tag, const QString& text, Waypoint* waypt);
   void start_something_else(QStringView el, const QXmlStreamAttributes& attr);
   void end_something_else();
   void tag_log_wpt(const QXmlStreamAttributes& attr) const;
@@ -346,117 +347,117 @@ private:
 
 // Maintain a fast mapping from full tag names to the struct above.
   const QHash<QString, tag_mapping> hash = {
-    {"/gpx", {tt_gpx, false}},
-    METATAG(tt_name, "name"),
-    METATAG(tt_desc, "desc"),
-    {"/gpx/author", {tt_author, false}},
-    {"/gpx/email", {tt_email, false}},
-    {"/gpx/url", {tt_url, false}},
-    {"/gpx/urlname", {tt_urlname, false}},
-    METATAG(tt_keywords, "keywords"),
-    {"/gpx/metadata/link", {tt_link, false}},
-    {"/gpx/metadata/link/text", {tt_link_text, false}},
-    {"/gpx/metadata/link/type", {tt_link_type, false}},
-
-    {"/gpx/wpt", {tt_wpt, false}},
+    {"/gpx", {tag_type::gpx, false}},
+    METATAG(tag_type::name, "name"),
+    METATAG(tag_type::desc, "desc"),
+    {"/gpx/author", {tag_type::author, false}},
+    {"/gpx/email", {tag_type::email, false}},
+    {"/gpx/url", {tag_type::url, false}},
+    {"/gpx/urlname", {tag_type::urlname, false}},
+    METATAG(tag_type::keywords, "keywords"),
+    {"/gpx/metadata/link", {tag_type::link, false}},
+    {"/gpx/metadata/link/text", {tag_type::link_text, false}},
+    {"/gpx/metadata/link/type", {tag_type::link_type, false}},
+
+    {"/gpx/wpt", {tag_type::wpt, false}},
 
     /* Double up the GPX 1.0 and GPX 1.1 styles */
 //     GEOTAG(tt_cache, "cache"),
-    {"/gpx/wpt/groundspeak:cache", {tt_cache, true}},
-
-    GEOTAG(tt_cache_name, "name"),
-    GEOTAG(tt_cache_container, "container"),
-    GEOTAG(tt_cache_type, "type"),
-    GEOTAG(tt_cache_difficulty, "difficulty"),
-    GEOTAG(tt_cache_terrain, "terrain"),
-    GEOTAG(tt_cache_hint, "encoded_hints"),
-    GEOTAG(tt_cache_desc_short, "short_description"),
-    GEOTAG(tt_cache_desc_long, "long_description"),
-    GEOTAG(tt_cache_placer, "owner"),
-    GEOTAG(tt_cache_favorite_points, "favorite_points"),
-    GEOTAG(tt_cache_personal_note, "personal_note"),
-    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:log_wpt", {tt_cache_log_wpt, true}},
-    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:type", {tt_cache_log_type, true}},
-    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:date", {tt_cache_log_date, true}},
-
-    {"/gpx/wpt/extensions", {tt_wpt_extensions, true}},
-
-    {GARMIN_WPT_EXT, {tt_garmin_wpt_extensions, true}},
-    {GARMIN_WPT_EXT "/gpxx:Proximity", {tt_garmin_wpt_proximity, true}},
-    {GARMIN_WPT_EXT "/gpxx:Temperature", {tt_garmin_wpt_temperature, true}},
-    {GARMIN_TRKPT_EXT "/gpxtpx:atemp", {tt_garmin_wpt_temperature, true}},
-    {GARMIN_WPT_EXT "/gpxx:Depth", {tt_garmin_wpt_depth, true}},
-    {GARMIN_WPT_EXT "/gpxx:DisplayMode", {tt_garmin_wpt_display_mode, true}},
-    {GARMIN_WPT_EXT "/gpxx:Categories", {tt_garmin_wpt_categories, true}},
-    {GARMIN_WPT_EXT "/gpxx:Categories/gpxx:Category", {tt_garmin_wpt_category, true}},
-    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:StreetAddress", {tt_garmin_wpt_addr, true}},
-    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:City", {tt_garmin_wpt_city, true}},
-    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:State", {tt_garmin_wpt_state, true}},
-    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:Country", {tt_garmin_wpt_country, true}},
-    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:PostalCode", {tt_garmin_wpt_postal_code, true}},
-    {GARMIN_WPT_EXT "/gpxx:PhoneNumber", {tt_garmin_wpt_phone_nr, true}},
+    {"/gpx/wpt/groundspeak:cache", {tag_type::cache, true}},
+
+    GEOTAG(tag_type::cache_name, "name"),
+    GEOTAG(tag_type::cache_container, "container"),
+    GEOTAG(tag_type::cache_type, "type"),
+    GEOTAG(tag_type::cache_difficulty, "difficulty"),
+    GEOTAG(tag_type::cache_terrain, "terrain"),
+    GEOTAG(tag_type::cache_hint, "encoded_hints"),
+    GEOTAG(tag_type::cache_desc_short, "short_description"),
+    GEOTAG(tag_type::cache_desc_long, "long_description"),
+    GEOTAG(tag_type::cache_placer, "owner"),
+    GEOTAG(tag_type::cache_favorite_points, "favorite_points"),
+    GEOTAG(tag_type::cache_personal_note, "personal_note"),
+    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:log_wpt", {tag_type::cache_log_wpt, true}},
+    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:type", {tag_type::cache_log_type, true}},
+    {"/gpx/wpt/groundspeak:cache/groundspeak:logs/groundspeak:log/groundspeak:date", {tag_type::cache_log_date, true}},
+
+    {"/gpx/wpt/extensions", {tag_type::wpt_extensions, true}},
+
+    {GARMIN_WPT_EXT, {tag_type::garmin_wpt_extensions, true}},
+    {GARMIN_WPT_EXT "/gpxx:Proximity", {tag_type::garmin_wpt_proximity, true}},
+    {GARMIN_WPT_EXT "/gpxx:Temperature", {tag_type::garmin_wpt_temperature, true}},
+    {GARMIN_TRKPT_EXT "/gpxtpx:atemp", {tag_type::garmin_wpt_temperature, true}},
+    {GARMIN_WPT_EXT "/gpxx:Depth", {tag_type::garmin_wpt_depth, true}},
+    {GARMIN_WPT_EXT "/gpxx:DisplayMode", {tag_type::garmin_wpt_display_mode, true}},
+    {GARMIN_WPT_EXT "/gpxx:Categories", {tag_type::garmin_wpt_categories, true}},
+    {GARMIN_WPT_EXT "/gpxx:Categories/gpxx:Category", {tag_type::garmin_wpt_category, true}},
+    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:StreetAddress", {tag_type::garmin_wpt_addr, true}},
+    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:City", {tag_type::garmin_wpt_city, true}},
+    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:State", {tag_type::garmin_wpt_state, true}},
+    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:Country", {tag_type::garmin_wpt_country, true}},
+    {GARMIN_WPT_EXT "/gpxx:Address/gpxx:PostalCode", {tag_type::garmin_wpt_postal_code, true}},
+    {GARMIN_WPT_EXT "/gpxx:PhoneNumber", {tag_type::garmin_wpt_phone_nr, true}},
 
     // In Garmin space, but in core of waypoint.
-    {GARMIN_TRKPT_EXT "/gpxtpx:hr", {tt_trk_trkseg_trkpt_heartrate, true}},
-    {GARMIN_TRKPT_EXT "/gpxtpx:cad", {tt_trk_trkseg_trkpt_cadence, true}},
-
-    {"/gpx/wpt/extensions/h:depth", {tt_humminbird_wpt_depth, true}},  // in centimeters.
-    {"/gpx/wpt/extensions/h:status", {tt_humminbird_wpt_status, true}},
-
-    {"/gpx/rte", {tt_rte, false}},
-    {"/gpx/rte/name", {tt_rte_name, false}},
-    {"/gpx/rte/desc", {tt_rte_desc, false}},
-    {"/gpx/rte/url", {tt_rte_url, false}},                                                     /* GPX 1.0 */
-    {"/gpx/rte/urlname", {tt_rte_urlname, false}},                     /* GPX 1.0 */
-    {"/gpx/rte/link", {tt_rte_link, false}},                                           /* GPX 1.1 */
-    {"/gpx/rte/link/text", {tt_rte_link_text, false}}, /* GPX 1.1 */
-    {"/gpx/rte/link/type", {tt_rte_link_type, false}}, /* GPX 1.1 */
-    {"/gpx/rte/number", {tt_rte_number, false}},
-    {GARMIN_RTE_EXT "/gpxx:DisplayColor", {tt_garmin_rte_display_color, true}},
-
-    {"/gpx/rte/rtept", {tt_rte_rtept, false}},
-
-    {"/gpx/trk", {tt_trk, false}},
-    {"/gpx/trk/name", {tt_trk_name, false}},
-    {"/gpx/trk/desc", {tt_trk_desc, false}},
-    {"/gpx/trk/trkseg", {tt_trk_trkseg, false}},
-    {"/gpx/trk/url", {tt_trk_url, false}},                                                     /* GPX 1.0 */
-    {"/gpx/trk/urlname", {tt_trk_urlname, false}},                     /* GPX 1.0 */
-    {"/gpx/trk/link", {tt_trk_link, false}},                                           /* GPX 1.1 */
-    {"/gpx/trk/link/text", {tt_trk_link_text, false}}, /* GPX 1.1 */
-    {"/gpx/trk/link/type", {tt_trk_link_type, false}}, /* GPX 1.1 */
-    {"/gpx/trk/number", {tt_trk_number, false}},
-    {GARMIN_TRK_EXT "/gpxx:DisplayColor", {tt_garmin_trk_display_color, true}},
-
-    {"/gpx/trk/trkseg/trkpt", {tt_trk_trkseg_trkpt, false}},
-    {"/gpx/trk/trkseg/trkpt/course", {tt_trk_trkseg_trkpt_course, false}},
-    {"/gpx/trk/trkseg/trkpt/speed", {tt_trk_trkseg_trkpt_speed, false}},
-
-    {"/gpx/trk/trkseg/trkpt/extensions/h:depth", {tt_humminbird_trk_trkseg_trkpt_depth, true}},        // in centimeters.
+    {GARMIN_TRKPT_EXT "/gpxtpx:hr", {tag_type::trk_trkseg_trkpt_heartrate, true}},
+    {GARMIN_TRKPT_EXT "/gpxtpx:cad", {tag_type::trk_trkseg_trkpt_cadence, true}},
+
+    {"/gpx/wpt/extensions/h:depth", {tag_type::humminbird_wpt_depth, true}},   // in centimeters.
+    {"/gpx/wpt/extensions/h:status", {tag_type::humminbird_wpt_status, true}},
+
+    {"/gpx/rte", {tag_type::rte, false}},
+    {"/gpx/rte/name", {tag_type::rte_name, false}},
+    {"/gpx/rte/desc", {tag_type::rte_desc, false}},
+    {"/gpx/rte/url", {tag_type::rte_url, false}},                                                      /* GPX 1.0 */
+    {"/gpx/rte/urlname", {tag_type::rte_urlname, false}},                      /* GPX 1.0 */
+    {"/gpx/rte/link", {tag_type::rte_link, false}},                                            /* GPX 1.1 */
+    {"/gpx/rte/link/text", {tag_type::rte_link_text, false}},  /* GPX 1.1 */
+    {"/gpx/rte/link/type", {tag_type::rte_link_type, false}},  /* GPX 1.1 */
+    {"/gpx/rte/number", {tag_type::rte_number, false}},
+    {GARMIN_RTE_EXT "/gpxx:DisplayColor", {tag_type::garmin_rte_display_color, true}},
+
+    {"/gpx/rte/rtept", {tag_type::rte_rtept, false}},
+
+    {"/gpx/trk", {tag_type::trk, false}},
+    {"/gpx/trk/name", {tag_type::trk_name, false}},
+    {"/gpx/trk/desc", {tag_type::trk_desc, false}},
+    {"/gpx/trk/trkseg", {tag_type::trk_trkseg, false}},
+    {"/gpx/trk/url", {tag_type::trk_url, false}},                                                      /* GPX 1.0 */
+    {"/gpx/trk/urlname", {tag_type::trk_urlname, false}},                      /* GPX 1.0 */
+    {"/gpx/trk/link", {tag_type::trk_link, false}},                                            /* GPX 1.1 */
+    {"/gpx/trk/link/text", {tag_type::trk_link_text, false}},  /* GPX 1.1 */
+    {"/gpx/trk/link/type", {tag_type::trk_link_type, false}},  /* GPX 1.1 */
+    {"/gpx/trk/number", {tag_type::trk_number, false}},
+    {GARMIN_TRK_EXT "/gpxx:DisplayColor", {tag_type::garmin_trk_display_color, true}},
+
+    {"/gpx/trk/trkseg/trkpt", {tag_type::trk_trkseg_trkpt, false}},
+    {"/gpx/trk/trkseg/trkpt/course", {tag_type::trk_trkseg_trkpt_course, false}},
+    {"/gpx/trk/trkseg/trkpt/speed", {tag_type::trk_trkseg_trkpt_speed, false}},
+
+    {"/gpx/trk/trkseg/trkpt/extensions/h:depth", {tag_type::humminbird_trk_trkseg_trkpt_depth, true}}, // in centimeters.
 
     /* Common to tracks, routes, and waypts */
-    GPXWPTTYPETAG("ele", tt_wpttype_ele, false),
-    GPXWPTTYPETAG("time", tt_wpttype_time, false),
-    GPXWPTTYPETAG("magvar", tt_wpttype_magvar, false),
-    GPXWPTTYPETAG("geoidheight", tt_wpttype_geoidheight, false),
-    GPXWPTTYPETAG("name", tt_wpttype_name, false),
-    GPXWPTTYPETAG("cmt", tt_wpttype_cmt, false),
-    GPXWPTTYPETAG("desc", tt_wpttype_desc, false),
-    GPXWPTTYPETAG("src", tt_wpttype_src, false),
-    GPXWPTTYPETAG("url", tt_wpttype_url, false),                                                       /* GPX 1.0 */
-    GPXWPTTYPETAG("urlname", tt_wpttype_urlname, false),                       /* GPX 1.0 */
-    GPXWPTTYPETAG("link", tt_wpttype_link, false),                                             /* GPX 1.1 */
-    GPXWPTTYPETAG("link/text", tt_wpttype_link_text, false),   /* GPX 1.1 */
-    GPXWPTTYPETAG("link/type", tt_wpttype_link_type, false),   /* GPX 1.1 */
-    GPXWPTTYPETAG("sym", tt_wpttype_sym, false),
-    GPXWPTTYPETAG("type", tt_wpttype_type, false),
-    GPXWPTTYPETAG("fix", tt_wpttype_fix, false),
-    GPXWPTTYPETAG("sat", tt_wpttype_sat, false),
-    GPXWPTTYPETAG("hdop", tt_wpttype_hdop, false),
-    GPXWPTTYPETAG("vdop", tt_wpttype_vdop, false),
-    GPXWPTTYPETAG("pdop", tt_wpttype_pdop, false),
-    GPXWPTTYPETAG("ageofdgpsdata", tt_wpttype_ageofdgpsdata, false),
-    GPXWPTTYPETAG("dgpsid", tt_wpttype_dgpsid, false),
+    GPXWPTTYPETAG("ele", tag_type::wpttype_ele, false),
+    GPXWPTTYPETAG("time", tag_type::wpttype_time, false),
+    GPXWPTTYPETAG("magvar", tag_type::wpttype_magvar, false),
+    GPXWPTTYPETAG("geoidheight", tag_type::wpttype_geoidheight, false),
+    GPXWPTTYPETAG("name", tag_type::wpttype_name, false),
+    GPXWPTTYPETAG("cmt", tag_type::wpttype_cmt, false),
+    GPXWPTTYPETAG("desc", tag_type::wpttype_desc, false),
+    GPXWPTTYPETAG("src", tag_type::wpttype_src, false),
+    GPXWPTTYPETAG("url", tag_type::wpttype_url, false),                                                        /* GPX 1.0 */
+    GPXWPTTYPETAG("urlname", tag_type::wpttype_urlname, false),                        /* GPX 1.0 */
+    GPXWPTTYPETAG("link", tag_type::wpttype_link, false),                                              /* GPX 1.1 */
+    GPXWPTTYPETAG("link/text", tag_type::wpttype_link_text, false),    /* GPX 1.1 */
+    GPXWPTTYPETAG("link/type", tag_type::wpttype_link_type, false),    /* GPX 1.1 */
+    GPXWPTTYPETAG("sym", tag_type::wpttype_sym, false),
+    GPXWPTTYPETAG("type", tag_type::wpttype_type, false),
+    GPXWPTTYPETAG("fix", tag_type::wpttype_fix, false),
+    GPXWPTTYPETAG("sat", tag_type::wpttype_sat, false),
+    GPXWPTTYPETAG("hdop", tag_type::wpttype_hdop, false),
+    GPXWPTTYPETAG("vdop", tag_type::wpttype_vdop, false),
+    GPXWPTTYPETAG("pdop", tag_type::wpttype_pdop, false),
+    GPXWPTTYPETAG("ageofdgpsdata", tag_type::wpttype_ageofdgpsdata, false),
+    GPXWPTTYPETAG("dgpsid", tag_type::wpttype_dgpsid, false),
   };
 
   QVector<arglist_t> gpx_args = {